namespace GGF
{
    using API;

    namespace REST
    {
        using System;
        using System.Net;
        using System.Text;
        using System.IO;
        using System.Diagnostics;

        using API;

        /// <summary>
        /// Class that creates an HTTP request for submission to the gubb API.
        /// Desired method and parameters built and returned using <c>currentAction</c> constructor
        /// parameter of abstract type <see cref="GGF.API.gAction"/>. Its concrete type will be either
        /// <see cref="GGF.API.gActionItem"/> or <see cref="GGF.API.gActionList"/>.
        /// </summary>
        public class gRequest
        {
            #region Fields

            string finalQueryString;
            HttpWebRequest request;
            StringBuilder finalQueryBuilder = new StringBuilder();
            int actionId;
            Uri fullUri;
            CredentialCache basicauthCache;
            bool isAuthApiKey;

            #endregion Fields

            #region Constructors

            /// <summary>
            /// Constructor for a gubb API request over HTTP.
            /// <remarks>
            /// Uses a standard
            /// <see cref="System.Net.HttpWebRequest"/> object to store header
            /// information.
            /// </remarks>
            /// </summary>
            /// <param name="currentAction">An abstract <see cref="GGF.API.gAction"/>
            /// which will be either a <see cref="GGF.API.gActionItem"/> or
            /// <see cref="GGF.API.gActionList"/>.</param>
            /// <param name="baseAddress">A string representing the base address
            /// of gubb API common to all calls. Should only represent the portion
            /// of the gubb API URL through the "api" identifier
            /// (<c>https://gubb.net/api/</c>).</param>
            /// <param name="currentCredentials">A <see cref="GGF.REST.gCred"/>
            /// object encapsulating the desired mode and tokens necessary for either
            /// API key or HTTP Basic authentication.</param>
            /// <returns>A "submit-ready" HTTP request
            /// object of type <see cref="GGF.REST.gRequest"/>.</returns>
            public gRequest(gAction currentAction, string baseAddress, gCred currentCredentials)
            {
                actionId = currentAction.getId();

                finalQueryBuilder.Append(baseAddress);

                if (currentAction.getElementType() == gElement.elementType.listMethod)
                    finalQueryBuilder.Append("list/");
                else
                    finalQueryBuilder.Append("item/");

                finalQueryBuilder.Append(currentAction.getQueryString());

                if (currentCredentials.isAPIkey)
                {
                    finalQueryBuilder.Append("&api_key=" + currentCredentials.getAPIkey());
                    isAuthApiKey = true;
                }
                else
                {
                    basicauthCache = new CredentialCache();
                    basicauthCache.Add(new Uri(baseAddress), "Basic", currentCredentials.getNamePass());
                    isAuthApiKey = false;
                }

                
                finalQueryString = finalQueryBuilder.ToString();

                fullUri = new Uri(finalQueryString);

                request = WebRequest.Create(fullUri) as HttpWebRequest;

                Debug.WriteLine("Final query string = " + finalQueryString, "Query string validation");

                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";

                if (!isAuthApiKey)
                    request.Credentials = basicauthCache;
    

                Debug.WriteLine("API request created for action with id = " + currentAction.getId(), "Request creation" );

            }

            #endregion Constructors

            #region Methods

            internal HttpWebRequest getRequestObj()
            {
                return request;
            }

            /// <summary>
            /// Returns an integer representing the id of the list or item acted upon, obtained
            /// from the action used to create this request.
            /// </summary>
            /// <returns>See summary.</returns>
            public int getActionId()
            {
                return actionId;
            }
            
            /// <summary>
            /// Returns a string representing method name, response type and parameters to be
            /// appended to base URI.
            /// </summary>
            /// <returns>See summary.</returns>
            public string getFinalQueryString()
            {
                return finalQueryString;
            }

            #endregion Methods
        }
    }
}